/**
 * @file   ModBundle.java
 * @author Enrique Madrid <e.madrid@lpcsite.com>
 * @date   Fri Sep 14 04:47:50 2007
 * 
 * @brief  
 * 
 * 
 */

package sim.bundle;


import java.util.Vector;
import java.util.Enumeration;

import sim.framework.*;
import sim.framework.io.*;
import sim.framework.dialog.*;
import sim.framework.gui.*;
import sim.utils.parser.*;
import sim.utils.Utils;

public abstract class ModBundle extends Module {

    protected static final int MOD_INSERT = -1;
    protected static final int MOD_MODIFY = -2;

    private static final String TITLE_LABEL = null;
    private static final String BADD_LABEL = "";
    private static final String BDEL_LABEL = "";
    private static final String BNEXT_LABEL = "";
    private static final String BBACK_LABEL = "";
    private static final String BHELP_LABEL = "";

    private Bundle m_Bundle = null;
    private int m_Return;

    private StringBuffer m_TextBuffer = new StringBuffer(64);

    private DlgBundle m_DlgMain;
    private DlgNotify m_DlgShow;
    
    public ModBundle(int id, Simlet s) {
        super(id, s);
    }

    private void showPopUp(final String message) {
        m_DlgMain.popUp(message, m_Simlet.getFontSys().medium);
        m_DlgMain.activeAll(false);
    }
    
    private void hidePopUp() {
        m_DlgMain.popUp_Close();
        m_DlgMain.activeAll(true);
        m_DlgMain.redraw();
    }
    
    public void work(final Msg msg) {
	switch (msg.getWParam()) {
	case Executable.STATE_INIT:
	    workInit(msg);
	    break;
	case Executable.STATE_NEXT:
	    workNext(msg);
	    break;
	case Executable.STATE_BACK:
	    workBack(msg);
	    break;
	}
    }

    private void workInit(final Msg msg) {
	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::workInit() ENTERED");
	//#endif

	// La clase derivada debe proveer un vector.
	m_Bundle = bundleCreate();
	// Si lo provee ...
	if (m_Bundle != null) {
	    // ... continuamos ...
	    if ((m_Bundle.getVector()).size() == 0) {
		execInsert();
	    } else {
                showDlgMain();
            }
	}
	else {
	    // ... en caso contrario abandonamos.
	    execBack();
	}

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::workInit() EXITING");
	//#endif

    }

    private void workNext(final Msg msg) {

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::workNext() ENTERED");
	//#endif
	switch (m_Return) {
	case MOD_INSERT:
	    //#ifdef DEBUG_MODBUNDLE
System.out.println("\tSe ha establecido un objeto para añadir");
	    //#endif
	    if (m_Bundle.get() != null) {
		// ... ejecutar el módulo MODIFY si lo hay.
		if (execModify()) {
		    break;
		}
	    }
	    // No pongas break aqui!!!.
	case MOD_MODIFY:
	    //#ifdef DEBUG_MODBUNDLE
System.out.println("\tInsertar el nuevo Item, redibular el dialogo principal");
	    //#endif
	    m_Bundle.insert();
	    showDlgMain();
	    break;
	}
	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::workNext() EXITING");
	//#endif
    }

    private void workBack(final Msg msg) {
	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::workBack() ENTERED");
	//#endif
	m_Bundle.reset();
	showDlgMain();
	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::workBack() EXITING");
	//#endif
    }

    private void showDlgMain() {
	// Mostrar el dialog principal.
	bundleCreateDlgs();
	fillCtrlList();
	setGui(m_DlgMain);
    }

    private void bundleCreateDlgs() {
	String showMe;

	// Recuperar la etiqueta del boton ?
	showMe = bundleShowMeLabel();

	// Crear el diálogo principal.
	m_DlgMain = (DlgBundle)DlgBundle.create(m_Simlet,
						bundleTitleLabel(),
						BADD_LABEL,
						BDEL_LABEL,
						BNEXT_LABEL,
						BBACK_LABEL,
						showMe);

	// Si se requiere el botón ? ...
	if ((showMe != null) && (m_DlgShow == null)) {
	    // Crear el diálogo para mostrar información.
	    m_DlgShow = (DlgNotify)DlgNotify.create(m_Simlet,
						    "",
						    null,
						    getLabel(Resource.LBL_CTRL_ACCEPT),
						    null);
	}
    }

    private void fillCtrlList() {
	Enumeration e;
	String string;
	Object item;

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::fillCtrlList() ENTERED");
	//#endif

	// Recorremos la lista de objetos asociados ...
	e = m_Bundle.elements();
	while(e.hasMoreElements()) {
	    // Recuperar el item
	    item = e.nextElement();
	    // Borrar el contenido del buffer temporal
	    appendText(null);
	    // Lamar al callback
	    bundleReDraw(item);
	    // Si el buffer temporal tiene datos ...
	    if (m_TextBuffer.length() > 0) {
		// ... pintarlos
		m_DlgMain.addText(Dialog.CTRL_MAIN, 
				  bundleItemId(item), 
				  m_TextBuffer);
	    }
	}

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::fillCtrlList() EXITING");
	//#endif

    }

    /**
     * CONTROLADORES DE EVENTOS DE INTERFAZ GRAFICA.
     * 
     */

    public boolean event(final Msg msg) {
	boolean ret;
	Gui gui;

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::event() ENTERED");
	//#endif

	ret = false;
	gui = getGui();
	if (gui.equals(m_DlgMain)) {
	    ret = eventMain(msg);
	}
	else if ((m_DlgShow != null) && (gui.equals(m_DlgShow))) {
	    ret = eventShow(msg);
	}

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::event() EXITING");
	//#endif

	return ret;
    }
    
    private boolean eventMain(final Msg msg) {
	boolean ret;
	Object item;

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::eventMain() ENTERED");
	//#endif

	ret = false;
	switch (msg.getEventCode()) {
	case EventListener.KEY_PRESSED:
	    if (m_DlgMain.getFocusID() == Dialog.CTRL_MAIN) {
		item = null;
		appendText(null);
		switch (msg.getWParam()) {
		case Gui.KEY_STAR:
		    item = bundleIdItem(m_DlgMain.getItemId(Dialog.CTRL_MAIN));
		    if (item != null) {
			bundleWhatIs(item);
		    }
		    break;
		case Gui.KEY_POUND:
		    item = bundleIdItem(m_DlgMain.getItemId(Dialog.CTRL_MAIN));
		    if (item != null) {
			bundleTellMe(item);
		    }
		    break;
		}
		if (m_TextBuffer.length() > 0) {
		    showPopUp(m_TextBuffer.toString());
		}
	    }
	    break;
	case EventListener.KEY_RELEASED:
	    switch (msg.getWParam()) {
	    case Gui.KEY_STAR:
	    case Gui.KEY_POUND:
		if (m_DlgMain.getFocusID() == Dialog.CTRL_MAIN) {
		    hidePopUp();
		}
	    }
	    break;
	case EventListener.COMMAND:
	    {
		switch (msg.getCtrlId()) {
		case Dialog.CTRL_MAIN:
		    ret = commandSelect();
		    break;
		case Dialog.CTRL_SOFTM:
		    switch (msg.getWParam()) {
		    case Dialog.CTRL_BUTTON_ADD:
			ret = commandInsert();
			break;
		    case Dialog.CTRL_BUTTON_DEL:
			ret = commandRemove();
			break;
		    case Dialog.CTRL_BUTTON_NEXT:
			ret = commandNext();
			break;
		    case Dialog.CTRL_BUTTON_BACK:
			ret = commandBack();
			break;
		    case Dialog.CTRL_BUTTON_HELP:
			ret = commandHelp();
			break;
		    }
		}
	    }
	}

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::eventMain() EXITING");
	//#endif

        return ret;
    }

    private boolean eventShow(final Msg msg) {
	boolean ret = false;

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::eventShow() ENTERED");
	//#endif

	switch (msg.getEventCode()) {
	case EventListener.COMMAND:
	    switch (msg.getWParam()) {
	    case Dialog.CTRL_BUTTON_NEXT:
		setGui(m_DlgMain);
		ret = true;
	    }
	}

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::eventShow() ENTERED");
	//#endif

	return ret;
    }

    /**
     * RESPUESTA A COMANDOS DE INTERFAZ GRAFICA
     * 
     */

    private boolean commandInsert() {
	execInsert();
	return true;
    }

    private boolean execInsert() {
	Module m = null;

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::execInsert() ENTERED");
	//#endif

	if ((m_Bundle.getFlags() & Bundle.FLAG_EDIT) == 0) {
	    m = createModule(ModBundle.MOD_INSERT);
	    if (m != null) {
		//#ifdef DEBUG_MODBUNDLE
System.out.println("\tEjecutando el módulo para insertar items ...");
		//#endif
		m_Return = MOD_INSERT;
		execQueue(this, this);
		exec(m);
	    }
	    //#ifdef DEBUG_MODBUNDLE
else {
System.out.println("\tNo hay un módulo asociado para insertar items!");
} 
	    //#endif

	}

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::execInsert() EXITING");
	//#endif

	return (m != null);
    }

    private boolean commandSelect() {
	Object item;
	// Si existe un item seleccionado ...
	item = bundleIdItem(m_DlgMain.getItemId(Dialog.CTRL_MAIN));
	if (m_Bundle.select(item)) {
	    execModify();
	}
	return true;
    }

    private boolean execModify() {
	Module m = null;

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::execModify() ENTERED");
	//#endif

	m = createModule(ModBundle.MOD_MODIFY);
	if (m != null) {
	    //#ifdef DEBUG_MODBUNDLE
System.out.println("\tEjecutando el módulo para modificar items ...");
	    //#endif
	    m_Return = MOD_MODIFY;
	    execQueue(this, this);
	    exec(m);
	}
	//#ifdef DEBUG_MODBUNDLE
else {
System.out.println("\tNo hay un módulo asociado para modificar items!");
} 
	//#endif

	//#ifdef DEBUG_MODBUNDLE
System.out.println("ModBundle::execModify() EXITING");
	//#endif

	return (m != null);
    }

    private boolean commandRemove() {
	Object item;
	item = bundleIdItem(m_DlgMain.getItemId(Dialog.CTRL_MAIN));
	if (item != null) {
	    m_Bundle.remove(item);
	    showDlgMain();
	}
	return true;
    }
    
    private boolean commandNext() {
	execNext();
	return true;
    }

    private boolean commandBack() {
	execBack();
	return true;
    }

    private boolean commandHelp() {
	Object item;
	// Si existe un item seleccionado ...
	item = bundleIdItem(m_DlgMain.getItemId(Dialog.CTRL_MAIN));
	if (item != null) {
	    // ... borrar el contenido de. buffer temporal
	    appendText(null);
	    // llamar al callback bundleShowMe().
	    bundleShowMe(item);
	    // Si se editó en el buffer temporal ...
	    if (m_TextBuffer.length() > 0) {
		// ... mostrarlo en el cuadro en la interfaz gráfica.
		m_DlgShow.setText(Dialog.CTRL_MAIN, m_TextBuffer);
		setGui(m_DlgShow);
	    }
	}
	return true;
    }

    /**
     * FUCIONES UTILIZADAS POR LOS CALLBACKS.
     * 
     */

    protected final void appendText(final String string) {
	// Si el parámetro es nulo ...
	if (string == null) {
	    // Borrar el buffer temporal
	    m_TextBuffer.setLength(0);
	}
	else {
	    // En caso contrario añadir text
	    m_TextBuffer.append(string);
	}
    }

    /**
     * METODOS DEFINIDOS Y REDEFINIDOS POR LA CLASE DERIVADA.
     * 
     */
    protected abstract Bundle bundleCreate();

    protected abstract void bundleReDraw(final Object item);

    protected void bundleWhatIs(final Object item) {
	appendText(null);
    }

    protected void bundleTellMe(final Object item) {
	appendText(null);
    }

    protected void bundleShowMe(final Object item) {
	appendText(null);
    }

    /** 
     * Título de la GUI principal.
     * 
     * @return Devuelve una referencia a un objeto String.
     */
    protected String bundleTitleLabel() {
	return TITLE_LABEL;
    }

    /** 
     * Devuelve la etiqueta del boton Showme
     *
     * Por defecto esta función devuelve null, lo que significa que el boton
     * para esta opción no esta disponible. La clase derivada puede redefinir
     * este comportamiento; por ejemplo, puede devolver "" para mostrar el
     * icono asociado con esta opción.
     * 
     * @return Devuelve una referencia a un objeto String.
     */
    protected String bundleShowMeLabel() {
	return null;
    }

    /** 
     * Devuelve el identificador de un objeto para la lista.
     * 
     * @param item Referencia a un objeto.
     * 
     * @return Devuelve un valor entero que identifica un objeto en la
     *         lista.
     */
    protected int bundleItemId(final Object item) {
	return m_Bundle.getId(item);
    }

    /** 
     * Devuelve un objeto de la lista dado su identificador.
     * 
     * @param itemId Identificador del objeto en la lista.
     * 
     * @return Si tiene éxito devuelve un objeto de la lista
     *         en caso contrario devuelve null.
     */
    protected Object bundleIdItem(int itemId) {
	return m_Bundle.getItem(itemId);
    }
}
